package controller;

import dto.ActionDTO;
import dto.ActionTypeEnum;
import dto.RespDTO;
import dto.RespStatusTypeEnum;
import model.command.CommandTypeEnum;
import service.Store;
import utils.LoggerUtil;

import java.io.*;
import java.net.Socket;
import java.util.HashMap;
import java.util.Map;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class SocketServerHandler implements Runnable {
    private final Logger LOGGER = LoggerFactory.getLogger(SocketServerHandler.class);
    private Socket socket;
    private Store store;
    private static final Map<ActionTypeEnum, Class<? extends CommandHandler>> handlerMap = new HashMap<>();

    static {
        handlerMap.put(ActionTypeEnum.GET, GetHandler.class);
        handlerMap.put(ActionTypeEnum.SET, SetHandler.class);
        handlerMap.put(ActionTypeEnum.RM, RmHandler.class);
    }

    public SocketServerHandler(Socket socket, Store store) {
        this.socket = socket;
        this.store = store;
    }

    @Override
    public void run() {
        //创建输入和输出流，用于从客户端读取对象和向客户端发送对象
        try (ObjectInputStream ois = new ObjectInputStream(socket.getInputStream());
             ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream())) {
            //从输入流中读取客户端发送的序列化对象
            ActionDTO dto = (ActionDTO) ois.readObject();
            LoggerUtil.debug(LOGGER, "[SocketServerHandler][ActionDTO]: {}", dto.toString());
            //根据反射, 获取对应的命令类型
            Class<? extends CommandHandler> handlerClass = handlerMap.get(dto.getType());
            if (handlerClass != null) {
                CommandHandler handler = handlerClass.getDeclaredConstructor().newInstance();
                RespDTO resp = handler.handle(dto, store);
                oos.writeObject(resp);
                oos.flush();
            } else {
                RespDTO resp = new RespDTO(CommandTypeEnum.NULL,RespStatusTypeEnum.FAIL, "Error: Unsupported Command Type!");
                oos.writeObject(resp);
                oos.flush();
            }

        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                socket.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}
